/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to jorya.txj@gmail.com
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/

/* 	2012-9  Created by jorya_txj
  *	xxxxxx   please added here
  */



#ifndef RAW_STM_H
#define RAW_STM_H


typedef RAW_U16 STM_SIGNAL;


typedef struct state_event {

	RAW_U16 sig;
	RAW_U8  ref_count;
	void    *which_pool; 
	
} STATE_EVENT;


typedef RAW_U16 (*stm_state_handler)(void *me, STATE_EVENT *e);
typedef RAW_U16 (*stm_action_handler)(void *me);
typedef struct RAW_QMSM_VTBL RAW_QMSM_VTBL;


typedef struct qm_state {
	
    struct qm_state *superstate;   /*!< superstate of this state */
    stm_state_handler stateHandler;  /*!< state handler function */
    stm_action_handler entryAction;   /*!< entry action handler function */
    stm_action_handler exitAction;    /*!< exit action handler function */
    stm_action_handler initAction;    /*!< init action handler function */
	
} QM_STATE;


typedef struct {
    QM_STATE        *target;
    stm_action_handler act[1];
} RAW_QM_TRAN_ACT_TABLE;


union RAW_QM_ATTR {
	
    QM_STATE        *obj;   /*!< pointer to QMState object */
    RAW_QM_TRAN_ACT_TABLE *tatbl; /*!< transition-action table */
    stm_state_handler  fun;          /*!< pointer to a state-handler function */
    stm_action_handler act;          /*!< pointer to an action-handler function */
};


typedef struct stm_struct {
	
	RAW_QMSM_VTBL *vptr; /*!< virtual pointer */
    union RAW_QM_ATTR state;   /*!< current active state (state-variable) */
    union RAW_QM_ATTR temp;    /*!< temporary: tran. chain, target state, etc. */
	
} STM_STRUCT;

struct RAW_QMSM_VTBL {
    /*! Triggers the top-most initial transition in a SM. */
    void (*init)(STM_STRUCT *me, STATE_EVENT *e);

    /*! Dispatches an event to a SM. */
    void (*dispatch)(STM_STRUCT *me, STATE_EVENT *e);
};


#define STM_SUCCESS             0
#define STM_MAX_NEST_DEPTH      6

#define STM_STATE_CAST(handler)  ((stm_state_handler)(handler))

enum {
    /* unhandled and need to "bubble up" */
    STM_RET_FATHER = 0,     /*!< event passed to superstate to handle */
    STM_RET_FATHER_SUB, /*!< event passed to submachine superstate */
    STM_RET_UNHANDLED, /*!< event unhandled due to a guard */

    /* handled and do not need to "bubble up" */
    STM_RET_HANDLED,   /*!< event handled (internal transition) */
    STM_RET_IGNORED,   /*!< event silently ignored (bubbled up to top) */

    /* entry/exit */
    STM_RET_ENTRY,     /*!< state entry action executed */
    STM_RET_EXIT,      /*!< state exit  action executed */

    /* no side effects */
    STM_RET_NULL,      /*!< return value without any effect */

    /* transitions need to execute transition-action table in QMsm */
    STM_RET_TRAN,      /*!< event handled (regular transition) */
    STM_RET_TRAN_INIT, /*!< initial transition in a state or submachine */
    STM_RET_TRAN_HIST, /*!< event handled (transition to history) */
    STM_RET_TRAN_EP,   /*!< entry-point transition into a submachine */
    STM_RET_TRAN_XP    /*!< exit-point transition out of a submachine */
};


#define STM_EMPTY_SIG           0

typedef enum raw_reserved_signals {

    STM_ENTRY_SIG = 1,                  
    STM_EXIT_SIG,                        
    STM_INIT_SIG,
    STM_TIMEOUT_SIG,                        
    STM_USER_SIG     
} RAW_RESERVED_SIGNALS;



extern STATE_EVENT STM_GLOBAL_EVENT[4];

#define RAW_Q_STATE_CAST(handler_)  ((stm_state_handler)(handler_))
#define RAW_Q_ACTION_CAST(action_)      ((stm_action_handler)(action_))

#define RAW_QM_ENTRY(dummy) (STM_RET_ENTRY)
#define RAW_QM_EXIT(dummy)  (STM_RET_EXIT)

#define STM_TRIG(state, sig) ((*(state))(me, &STM_GLOBAL_EVENT[sig]))
#define STM_ENTER(state) STM_TRIG((state), STM_ENTRY_SIG)
#define STM_EXIT(state)  STM_TRIG((state), STM_EXIT_SIG)

#define STM_TRAN(state)  (((STM_STRUCT *)me)->temp.fun = STM_STATE_CAST(state), STM_RET_TRAN)
#define STM_FATHER(father)      (((STM_STRUCT *)me)->temp.fun = STM_STATE_CAST(father),  STM_RET_FATHER)

#define RAW_Q_DIM(array_) (sizeof(array_) / sizeof((array_)[0]))

#define RAW_MSM_INIT(me_, e_) ((*(me_)->vptr->init)((me_), (e_)))
#define RAW_MSM_DISPATCH(me_, e_) ((*(me_)->vptr->dispatch)((me_), (e_)))


#define RAW_Q_MSM_UPCAST(ptr_) ((STM_STRUCT *)(ptr_))


/*! Macro to call in a QM state-handler when it executes a regular
* transition. Applicable only to QMSMs.
*/
#define RAW_QM_TRAN(tatbl_) \
    ((RAW_Q_MSM_UPCAST(me))->temp.tatbl = (RAW_QM_TRAN_ACT_TABLE *)(tatbl_), \
        STM_RET_TRAN)

/*! Macro to call in a QM state-handler when it executes an initial
* transition. Applicable only to QMSMs.
*/
#define RAW_QM_TRAN_INIT(tatbl_) \
    ((RAW_Q_MSM_UPCAST(me))->temp.tatbl = (RAW_QM_TRAN_ACT_TABLE *)(tatbl_), \
        STM_RET_TRAN_INIT)

/*! Macro to call in a QM state-handler when it executes a transition
* to history. Applicable only to QMSMs.
*/
#define RAW_QM_TRAN_HIST(history_, tatbl_) \
    ((((RAW_Q_MSM_UPCAST(me))->state.obj = (history_)), \
      ((RAW_Q_MSM_UPCAST(me))->temp.tatbl = (RAW_QM_TRAN_ACT_TABLE *)(tatbl_))), \
       STM_RET_TRAN_HIST)

/*! Macro to call in a QM state-handler when it executes a transition
* to the submachine via an entry point.
*/
#define RAW_QM_TRAN_EP(tatbl_) \
    ((RAW_Q_MSM_UPCAST(me))->temp.tatbl = (RAW_QM_TRAN_ACT_TABLE *)(tatbl_), \
        STM_RET_TRAN_EP)

/*! Macro to call in a QM state-handler when it executes a transition
* to exit point. Applicable only to QMSMs.
*/
#define RAW_QM_TRAN_XP(xp_, tatbl_) \
    ((((RAW_Q_MSM_UPCAST(me))->state.act = (xp_)), \
        ((RAW_Q_MSM_UPCAST(me))->temp.tatbl = (RAW_QM_TRAN_ACT_TABLE *)(tatbl_))),\
        STM_RET_TRAN_XP)

/*! Macro to call in a QM state-handler when it handled an event.
* Applicable only to QMSMs.
*/
#define RAW_QM_HANDLED()     (STM_RET_HANDLED)

/*! Macro to call in a QM state-handler when when it attempts to
* handle an event but a guard condition evaluates to 'false' and there is
* no other explicit way of handling the event. Applicable only to QMSMs.
*/
#define RAW_QM_UNHANDLED()   (STM_RET_UNHANDLED)

/*! Macro to call in a QM state-handler when it designates the
* superstate to handle an event. Applicable only to QMSMs.
*/
#define RAW_QM_SUPER()       (STM_RET_FATHER)

/*! Macro to call in a QM submachine-handler when it designates the
* host state to handle an event. Applicable only to QMSMs.
*/
#define RAW_QM_SUPER_SUB(host_) \
    ((RAW_Q_MSM_UPCAST(me))->temp.obj = (host_), STM_RET_FATHER_SUB)



RAW_U16 raw_hsm_top(void  *me, STATE_EVENT *e);

void hsm_constructor(STM_STRUCT *me, stm_state_handler initial);
void fsm_constructor(STM_STRUCT *me, stm_state_handler initial);
void msm_constructor(STM_STRUCT *me, stm_state_handler initial);

void raw_fsm_init(STM_STRUCT *me, STATE_EVENT *e); 
void raw_fsm_exceute(STM_STRUCT *me, STATE_EVENT *e); 
void raw_hsm_init(STM_STRUCT *me, STATE_EVENT *e);
void raw_hsm_exceute(STM_STRUCT *me, STATE_EVENT *e);
RAW_U16 raw_is_hsm_in_state(STM_STRUCT *me, stm_state_handler state);
stm_state_handler raw_hsm_child_state(STM_STRUCT *me, stm_state_handler parent);

void raw_msm_init(STM_STRUCT *me, STATE_EVENT *e);
void raw_msm_exceute(STM_STRUCT *me, STATE_EVENT *e);
RAW_U16 raw_is_msm_in_state(STM_STRUCT *me, QM_STATE *state);
QM_STATE *raw_msm_child_state(STM_STRUCT *me, QM_STATE *parent);

#endif

